home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DJGPP / ZIP191SR.ZIP / src / infozip / zip19p1 / fileio.c < prev    next >
C/C++ Source or Header  |  1993-11-21  |  59KB  |  2,113 lines

  1. /*
  2.  
  3.  Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly,
  4.  Kai Uwe Rommel and Igor Mandrichenko.
  5.  Permission is granted to any individual or institution to use, copy, or
  6.  redistribute this software so long as all of the original files are included
  7.  unmodified, that it is not sold for profit, and that this copyright notice
  8.  is retained.
  9.  
  10. */
  11.  
  12. /*
  13.  *  fileio.c by Mark Adler.
  14.  */
  15.  
  16. #include "zip.h"
  17.  
  18. #include <time.h>
  19.  
  20. #ifdef WIN32
  21. #  include <sys/utime.h>
  22. #  include <windows.h> /* for findfirst/findnext */
  23. #endif
  24.  
  25. #ifdef MACOS
  26. #  define EXDEV 1
  27. #endif
  28.  
  29. #ifdef OSF
  30. #  define EXDEV 18    /* avoid a bug in the DEC OSF/1 header files. */
  31. #else
  32. #  include <errno.h>
  33. #endif
  34.  
  35. #ifdef MINIX
  36. #  ifdef S_IWRITE
  37. #    undef S_IWRITE
  38. #  endif /* S_IWRITE */
  39. #  define S_IWRITE S_IWUSR
  40. #endif /* S_IWUSR */
  41.  
  42. #ifdef ATARI_ST
  43. #  undef MSDOS
  44. #endif
  45.  
  46. #ifdef MSDOS
  47. #  include <io.h>
  48. #  if (defined(__TURBOC__) || defined(__GO32__))
  49. #    include <dir.h>
  50. #  else /* !__TURBOC__ */
  51. #    if !defined(__EMX__) && !defined(__WATCOMC__)
  52. #      include <direct.h>
  53. #    endif
  54. #  endif /* ?__TURBOC__ */
  55. #  define link rename
  56. #  ifdef OS2
  57. #    define MATCH shmatch
  58. #  else /* !OS2 */
  59. #    define MATCH dosmatch
  60. #  endif /* ?OS2 */
  61. #else /* !MSDOS */
  62.    extern int errno;    /* error number from system functions */
  63. #  ifdef VMS
  64. #    define RMDIR
  65. #    define link rename
  66. #    include "VMSmunch.h"
  67. #  endif /* VMS */
  68. #  ifdef MACOS
  69. #    define link rename
  70. #    define mktemp tmpnam
  71. #  endif
  72. #  define MATCH shmatch
  73. #endif /* ?MSDOS */
  74.  
  75. #ifdef ATARI_ST
  76. #  define MSDOS 1
  77. #endif
  78.  
  79. #ifdef UTS
  80. #  define RMDIR
  81. #endif /* UTS */
  82.  
  83.  
  84. /* Extra malloc() space in names for cutpath() */
  85. #ifdef VMS
  86. #  define PAD 3         /* may have to change .FOO] to ]FOO.DIR */
  87. #else /* !VMS */
  88. #  define PAD 0
  89. #endif /* ?VMS */
  90.  
  91.  
  92. /* For now, assume DIRENT implies System V implies TERMIO */
  93. #if defined(DIRENT) && !defined(MINIX) && !defined(TERMIO)
  94. #  define TERMIO
  95. #endif
  96.  
  97.  
  98. #ifdef CRYPT
  99. #  ifdef MSVMS
  100. #    ifdef MSDOS
  101. #      ifdef __EMX__
  102. #        define getch() _read_kbd(0, 1, 0)
  103. #      else
  104. #        ifdef __GO32__
  105. #          include <pc.h>
  106. #          define getch() getkey()
  107. #        else
  108. #          include <conio.h>
  109. #        endif
  110. #      endif
  111. #    else /* !MSDOS */
  112. #      define getch() getc(stderr)
  113. #      define echoff(f) echo(0)   /* for echo control */
  114. #      define echon()   echo(1)
  115. #      include <iodef.h>
  116. #      include <ttdef.h>
  117. #      if !defined(SS$_NORMAL)
  118. #        define SS$_NORMAL 1   /* only thing we need from <ssdef.h> */
  119. #      endif
  120. #    endif /* ?MSDOS */
  121. #  else /* !MSVMS */
  122. #    ifdef TERMIO       /* Amdahl, Cray, all SysV? */
  123. #      ifdef CONVEX
  124. #        include <sys/termios.h>
  125. #        include <sgtty.h>
  126. #        define O_BINARY 0
  127. #      else /* !CONVEX */
  128. #        ifdef LINUX 
  129. #          include <termios.h>
  130. #        else /* !LINUX */
  131. #          include <sys/termio.h>
  132. #        endif /* ?LINUX */
  133. #        define sgttyb termio
  134. #        define sg_flags c_lflag
  135.          int ioctl OF((int, int, voidp *));
  136. #      endif /* ?CONVEX */
  137. #      define GTTY(f,s) ioctl(f,TCGETA,s)
  138. #      define STTY(f,s) ioctl(f,TCSETAW,s)
  139. #    else /* !TERMIO */
  140. #      ifndef MINIX
  141. #        include <sys/ioctl.h>
  142. #      endif /* !MINIX */
  143. #      include <sgtty.h>
  144.        int gtty OF((int, struct sgttyb *));
  145.        int stty OF((int, struct sgttyb *));
  146. #      define GTTY gtty
  147. #      define STTY stty
  148. #    endif /* ?TERMIO */
  149.      int isatty OF((int));
  150.      char *ttyname OF((int));
  151.      int open OF((char *, int, ...));
  152.      int close OF((int));
  153.      int read OF((int, voidp *, int));
  154. #  endif /* ?MSVMS */
  155. #endif /* ?CRYPT */
  156.  
  157. #ifdef VMS
  158. #  include <descrip.h>
  159. #  include <rms.h>
  160. #endif
  161.  
  162. /* For directory access. (This is getting rather messy. Cleanup
  163.  * scheduled for version 17.9.)
  164.  */
  165. #ifndef UTIL
  166.  
  167. #ifdef SYSV                     /* use readdir()  */
  168. #  include <dirent.h>
  169. #  define dstrm DIR
  170. #  define direct dirent
  171. #else
  172.  
  173. #ifdef DIRENT                   /* use getdents() */
  174. #  if defined(MINIX) || defined(OSF)
  175. #    include <dirent.h>
  176. #  else /* !MINIX */
  177. #    include <sys/dirent.h>
  178. #  endif /* ?MINIX */
  179. #  define direct dirent
  180. #  ifdef MINIX
  181.      int getdents OF((int, char *, unsigned));
  182. #  else /* !MINIX */
  183.      int getdents OF((int, char *, int));
  184. #  endif /* ?MINIX */
  185. #  define DBSZ 4096     /* This has to be bigger than a directory block */
  186.    typedef struct {     /* directory stream buffer */
  187.      int f;             /* file descriptor for the directory "file" */
  188.      char *p;           /* pointer to next entry in buffer */
  189.      char *q;           /* pointer after end of buffer contents */
  190.      char b[DBSZ];              /* buffer */
  191.    } dstrm;
  192.  
  193. #else /* !DIRENT */             /* use opendir(), etc. */
  194. #  if defined(CONVEX) || defined(ultrix)
  195. #    include <dirent.h>
  196. #    ifdef direct
  197. #      undef direct /* ultrix 4.2, at least if !__POSIX */
  198. #    endif
  199. #    define direct dirent
  200. #  endif /* CONVEX || ultrix */
  201. #  ifdef NDIR
  202. #    include "ndir.h"           /* for HPUX */
  203. #  else /* !NDIR */
  204. #    ifdef MSDOS
  205. #     ifdef OS2
  206. #      include "os2zip.h"
  207. #     else /* !OS2 */
  208. #      ifndef ATARI_ST
  209. #        include <dos.h>
  210. #      endif
  211. #      if (defined(__TURBOC__) || defined(__GO32__))
  212. #        define FATTR           FA_HIDDEN+FA_SYSTEM+FA_DIREC
  213. #        define FFIRST(n,d)     findfirst(n,(struct ffblk *)d,FATTR)
  214. #        define FNEXT(d)        findnext((struct ffblk *)d)
  215. #      else /* !__TURBOC__ */
  216. #        define FATTR           _A_HIDDEN+_A_SYSTEM+_A_SUBDIR
  217. #        define FFIRST(n,d)     _dos_findfirst(n,FATTR,(struct find_t *)d)
  218. #        define FNEXT(d)        _dos_findnext((struct find_t *)d)
  219. #      endif /* ?__TURBOC__ */
  220. #      if defined(__GO32__)
  221. #        include <sys/dirent.h>
  222. #        define direct dirent
  223. #      else /* !__GO32__ */
  224.        typedef struct direct {
  225.          char d_reserved[30];
  226.          char d_name[13];
  227.      int d_first;
  228. #ifdef WIN32
  229.      HANDLE d_hFindFile;
  230. #endif
  231.        } DIR;
  232. #      endif /* ?__GO32__ */
  233. #     endif /* ?OS2 */
  234. #    else /* !MSDOS */
  235. #      ifdef VMS
  236. #        include <ssdef.h>
  237.          typedef struct direct {
  238.              int d_wild;                /* flag for wildcard vs. non-wild */
  239.              struct FAB fab;
  240.              struct NAM nam;
  241.              char d_qualwildname[NAM$C_MAXRSS + 1];
  242.              char d_name[NAM$C_MAXRSS + 1];
  243.          } DIR;
  244. #      else /* !VMS */
  245. #        ifdef MACOS
  246.            typedef struct direct {
  247.              int d_wild;                /* flag for wildcard vs. non-wild */
  248.              char *d_name;
  249.           } DIR;
  250. #        endif
  251. #        ifdef M_XENIX
  252. #          include <sys/ndir.h>
  253. #        else /* !M_XENIX */
  254. #          include <sys/dir.h>
  255. #        endif /* ?M_XENIX */
  256. #        ifdef NODIR                    /* for AT&T 3B1 */
  257. #          define dirent direct
  258.            typedef FILE DIR;
  259. #          define dstrm DIR
  260. #        endif /* NODIR */
  261. #      endif /* ?VMS */
  262. #    endif /* ?MSDOS */
  263. #  endif /* ?NDIR */
  264. #  define dstrm DIR
  265. #  ifndef NODIR
  266.      DIR *opendir OF((char *));
  267. #  endif /* !NODIR */
  268. #  ifndef CONVEX
  269.      struct direct *readdir OF((DIR *));
  270. #  endif /* !CONVEX */
  271. #endif /* ?DIRENT */
  272. #endif /* ?SYSV */
  273. #endif /* !UTIL */
  274.  
  275.  
  276. /* Library functions not in (most) header files */
  277.  
  278. #if defined(__IBMC__) || defined(__WATCOMC__)
  279. #  define NO_MKTEMP
  280. #endif
  281. char *mktemp OF((char *));
  282.  
  283. #ifdef __GO32__
  284.   char *strlwr OF((char *));
  285. #else
  286.   int link OF((char *, char *));
  287.   int unlink OF((char *));
  288. # if defined(MSDOS)
  289.    int chmod OF((char *, int));
  290.    /* For many targets, chmod is already defined by sys/stat.h, and second
  291.     * parameter is an unsigned long.
  292.     */
  293. # endif
  294. #endif
  295.  
  296.  
  297. #ifndef UTIL    /* the companion #endif is a bit of ways down ... */
  298.  
  299. #ifndef __TURBOC__
  300.    int utime OF((char *, time_t *));
  301. #endif /* !__TURBOC__ */
  302. #ifndef MSDOS
  303.    int open OF((char *, int, ...));
  304.    int close OF((int));
  305. #  ifndef RMDIR
  306.      int rmdir OF((char *));
  307. #  endif /* !RMDIR */
  308. #endif /* !MSDOS */
  309.  
  310.  
  311. /* Local globals (kinda like "military intelligence" or "broadcast quality") */
  312. local int exflag = 0;           /* Exclude flag */
  313.  
  314. #ifdef VMS
  315.   typedef int statime;
  316. #else /* !VMS */
  317.   typedef time_t statime;
  318. #endif /* ?VMS */
  319.  
  320. /* Local functions */
  321. #ifdef PROTO
  322. #  ifdef VMS
  323.      local void vms_wild(char *, dstrm *);
  324. #  endif /* VMS */
  325. #  ifdef DIRENT
  326.      local dstrm *opend(char *);
  327.      local void closed(dstrm *);
  328. #  endif /* DIRENT */
  329.    local char *readd(dstrm *);
  330.    local int fqcmp(voidp *, voidp *);
  331.    local int fqcmpz(voidp *, voidp *);
  332.    local char *last(char *);
  333.    local char *msname(char *);
  334. #  ifdef VMS
  335.      local char *strlower(char *);
  336.      local char *strupper(char *);
  337. #  endif /* VMS */
  338.    local char *ex2in(char *, int *);
  339.    local int newname(char *);
  340.    local void inctime(struct tm *);
  341.    local ulg unix2dostime(statime *);
  342. #  if !defined(__TURBOC__) && !defined(OS2) && !defined(__GO32__)
  343.      local int cmptime(struct tm *, struct tm *);
  344.      local time_t invlocal(struct tm *);
  345. #  endif /* !__TURBOC__ */
  346. #endif /* PROTO */
  347.  
  348.  
  349. #if defined(MSDOS) && !defined(OS2) && !defined(__GO32__)
  350. dstrm *opendir(n)
  351. char *n;                /* directory to open */
  352. /* Start searching for files in the MSDOS directory n */
  353. {
  354.   dstrm *d;             /* malloc'd return value */
  355.   char *p;              /* malloc'd temporary string */
  356.  
  357.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL ||
  358.       (p = malloc(strlen(n) + 5)) == NULL)
  359.     return NULL;
  360.   strcat(strcpy(p, n), "/*.*");
  361. #ifdef WIN32
  362.   {
  363.   WIN32_FIND_DATA fd;
  364.   DWORD dwAttr;
  365.   BOOL bAttr;
  366.  
  367.   if ((HANDLE)0xFFFFFFFF == (d->d_hFindFile = FindFirstFile(p, &fd)))
  368.     {
  369.     free((voidp *)p);
  370.     return NULL;
  371.     }
  372.   else
  373.     strcpy(d->d_name, fd.cFileName);
  374.   if (-1 != (dwAttr = GetFileAttributes(fd.cFileName)))
  375.     {
  376.     bAttr = FALSE;
  377.     if (FILE_ATTRIBUTE_SYSTEM == (dwAttr & FILE_ATTRIBUTE_SYSTEM))
  378.     bAttr = TRUE;
  379.     if (FILE_ATTRIBUTE_HIDDEN == (dwAttr & FILE_ATTRIBUTE_HIDDEN))
  380.     bAttr = TRUE;
  381.     if (FILE_ATTRIBUTE_DIRECTORY == (dwAttr & FILE_ATTRIBUTE_DIRECTORY))
  382.     bAttr = TRUE;
  383.     if (!bAttr)
  384.     {
  385.     free ((voidp *)p);
  386.     free ((void *) d);
  387.     return NULL;
  388.     }
  389.     }
  390.  
  391.   }
  392. #else
  393.   if (FFIRST(p, d))
  394.   {
  395.     free((voidp *)p);
  396.     return NULL;
  397.   }
  398.   free((voidp *)p);
  399. #endif
  400.   d->d_first = 1;
  401.   return d;
  402. }
  403.  
  404. struct direct *readdir(d)
  405. dstrm *d;               /* directory stream to read from */
  406. /* Return pointer to first or next directory entry, or NULL if end. */
  407. {
  408.   if (d->d_first)
  409.     d->d_first = 0;
  410.   else
  411. #ifdef WIN32
  412.     {
  413.     WIN32_FIND_DATA fd;
  414.  
  415.     if (!FindNextFile(d->d_hFindFile, &fd))
  416.     return NULL;
  417.     else
  418.     strcpy(d->d_name, fd.cFileName);
  419.     }
  420. #else /* !WIN32 */
  421.     if (FNEXT(d))
  422.       return NULL;
  423. #endif
  424.   return (struct direct *)d;
  425. }
  426. #  define closedir free
  427.  
  428. #endif /* MSDOS && !OS2 */
  429.  
  430.  
  431. #ifdef VMS
  432.  
  433. /*---------------------------------------------------------------------------
  434.  
  435.     _vms_findfirst() and _vms_findnext(), based on public-domain DECUS C
  436.     fwild() and fnext() routines (originally written by Martin Minow, poss-
  437.     ibly modified by Jerry Leichter for bintnxvms.c), were written by Greg
  438.     Roelofs and are still in the public domain.  Routines approximate the
  439.     behavior of MS-DOS (MSC and Turbo C) findfirst and findnext functions.
  440.  
  441.   ---------------------------------------------------------------------------*/
  442. local void vms_wild(p, d)
  443. char *p;
  444. dstrm *d;
  445. {
  446.   /*
  447.    * Do wildcard setup
  448.    */
  449.   /* set up the FAB and NAM blocks. */
  450.   d->fab = cc$rms_fab;             /* initialize fab */
  451.   d->nam = cc$rms_nam;             /* initialize nam */
  452.  
  453.   d->fab.fab$l_nam = &d->nam;           /* fab -> nam */
  454.   d->fab.fab$l_fna = p;                 /* argument wild name */
  455.   d->fab.fab$b_fns = strlen(p);         /* length */
  456.  
  457.   d->nam.nam$l_esa = d->d_qualwildname; /* qualified wild name */
  458.   d->nam.nam$b_ess = NAM$C_MAXRSS;      /* max length */
  459.   d->nam.nam$l_rsa = d->d_name;         /* matching file name */
  460.   d->nam.nam$b_rss = NAM$C_MAXRSS;      /* max length */
  461.  
  462.   /* parse the file name */
  463.   if (sys$parse(&d->fab) != RMS$_NORMAL)
  464.     return;
  465.   /* Does this replace d->fab.fab$l_fna with a new string in its own space?
  466.      I sure hope so, since p is free'ed before this routine returns. */
  467.  
  468.   /* have qualified wild name (i.e., disk:[dir.subdir]*.*); null-terminate
  469.    * and set wild-flag */
  470.   d->d_qualwildname[d->nam.nam$b_esl] = '\0';
  471.   d->d_wild = (d->nam.nam$l_fnb & NAM$M_WILDCARD)? 1 : 0;   /* not used... */
  472. #ifdef DEBUG
  473.   printf("  incoming wildname:  %s\n", p);
  474.   printf("  qualified wildname:  %s\n", d->d_qualwildname);
  475. #endif /* DEBUG */
  476. }
  477.  
  478. dstrm *opendir(n)
  479. char *n;                /* directory to open */
  480. /* Start searching for files in the VMS directory n */
  481. {
  482.   char *c;              /* scans VMS path */
  483.   dstrm *d;             /* malloc'd return value */
  484.   int m;                /* length of name */
  485.   char *p;              /* malloc'd temporary string */
  486.  
  487.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL ||
  488.       (p = malloc((m = strlen(n)) + 4)) == NULL)
  489.     return NULL;
  490.   /* Directory may be in form "[DIR.SUB1.SUB2]" or "[DIR.SUB1]SUB2.DIR;1".
  491.      If latter, convert to former. */
  492.   if (m > 0  &&  *(c = strcpy(p,n)+m-1) != ']')
  493.   {
  494.     while (--c > p  &&  *c != ';')
  495.       ;
  496.     if (c-p < 5  ||  strncmp(c-4, ".DIR", 4))
  497.     {
  498.       free((voidp *)d);  free((voidp *)p);
  499.       return NULL;
  500.     }
  501.     c -= 3;
  502.     *c-- = '\0';        /* terminate at "DIR;#" */
  503.     *c = ']';           /* "." --> "]" */
  504.     while (c > p  &&  *--c != ']')
  505.       ;
  506.     *c = '.';           /* "]" --> "." */
  507.   }
  508.   strcat(p, "*.*");
  509.   vms_wild(p, d);       /* set up wildcard */
  510.   free((voidp *)p);
  511.   return d;
  512. }
  513.  
  514. struct direct *readdir(d)
  515. dstrm *d;               /* directory stream to read from */
  516. /* Return pointer to first or next directory entry, or NULL if end. */
  517. {
  518.   int r;                /* return code */
  519.  
  520.   do {
  521.     d->fab.fab$w_ifi = 0;       /* internal file index:  what does this do? */
  522.  
  523.     /* get next match to possible wildcard */
  524.     if ((r = sys$search(&d->fab)) == RMS$_NORMAL)
  525.     {
  526.         d->d_name[d->nam.nam$b_rsl] = '\0';   /* null terminate */
  527.         return (struct direct *)d;   /* OK */
  528.     }
  529.   } while (r == RMS$_PRV);
  530.   return NULL;
  531. }
  532. #  define closedir free
  533. #endif /* VMS */
  534.  
  535.  
  536. #ifdef NODIR                    /* for AT&T 3B1 */
  537. /*
  538. **  Apparently originally by Rich Salz.
  539. **  Cleaned up and modified by James W. Birdsall.
  540. */
  541.  
  542. #  define opendir(path) fopen(path, "r")
  543.  
  544. struct direct *readdir(dirp)
  545. DIR *dirp;
  546. {
  547.   static struct direct entry;
  548.  
  549.   if (dirp == NULL) 
  550.     return NULL;
  551.   for (;;)
  552.     if (fread (&entry, sizeof (struct direct), 1, dirp) == 0) 
  553.       return NULL;
  554.     else if (entry.d_ino) 
  555.       return (&entry);
  556. } /* end of readdir() */
  557.  
  558. #  define closedir(dirp) fclose(dirp)
  559. #endif /* NODIR */
  560.  
  561.  
  562. #ifdef DIRENT
  563. local dstrm *opend(n)
  564. char *n;                /* directory name to open */
  565. /* Open the directory *n, returning a pointer to an allocated dstrm, or
  566.    NULL if error. */
  567. {
  568.   dstrm *d;             /* pointer to malloc'ed directory stream */
  569.  
  570.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
  571.     return NULL;
  572.   if ((d->f = open(n, 0, 0)) < 0)               /* open directory */
  573.     return NULL;
  574.   d->p = d->q = d->b;                           /* buffer is empty */
  575.   return d;
  576. }
  577. #else /* !DIRENT */
  578. #  define opend opendir                         /* just use opendir() */
  579. #endif /* ?DIRENT */
  580.  
  581.  
  582. local char *readd(d)
  583. dstrm *d;               /* directory stream to read from */
  584. /* Return a pointer to the next name in the directory stream d, or NULL if
  585.    no more entries or an error occurs. */
  586. {
  587.   struct direct *e;     /* directory entry read */
  588.  
  589. #ifdef DIRENT
  590.   int n;                /* number of entries read by getdents */
  591.  
  592.   if (d->p >= d->q)                             /* if empty, fill buffer */
  593.     if ((n = getdents(d->f, d->b, DBSZ)) <= 0)
  594.       return NULL;
  595.     else
  596.       d->q = n + (d->p = d->b);
  597.   e = (struct direct *)(d->p);                  /* point to entry */
  598.   d->p += ((struct direct *)(d->p))->d_reclen;  /* advance */
  599.   return e->d_name;                             /* return name */
  600. #else /* !DIRENT */
  601.   return (e = readdir(d)) == NULL ? (char *)NULL : e->d_name;
  602. #endif /* ?DIRENT */
  603. }
  604.  
  605.  
  606. #ifdef DIRENT
  607. local void closed(d)
  608. dstrm *d;               /* directory stream to close */
  609. /* Close the directory stream */
  610. {
  611.   close(d->f);
  612.   free((voidp *)d);
  613. }
  614. #else /* !DIRENT */
  615. #  define closed closedir
  616. #endif /* ?DIRENT */
  617.  
  618.  
  619. #ifdef MSDOS
  620.  
  621. int wild(w)
  622. char *w;                /* path/pattern to match */
  623. /* If not in exclude mode, expand the pattern based on the contents of the
  624.    file system.  Return an error code in the ZE_ class. */
  625. {
  626.   char *a;              /* alloc'ed space for name */
  627.   dstrm *d;             /* stream for reading directory */
  628.   char *e;              /* name found in directory */
  629.   int f;                /* true if there was a match */
  630.   char *n;              /* constructed name from directory */
  631.   char *p;              /* path */
  632.   char *q;              /* name */
  633.   int r;                /* temporary variable */
  634.   char v[5];            /* space for device current directory */
  635.  
  636.   /* Allocate and copy pattern */
  637.   if ((p = a = malloc(strlen(w) + 1)) == NULL)
  638.     return ZE_MEM;
  639.   strcpy(p, w);
  640.  
  641.   /* Normalize pattern to upper case, path delimiter as '/'. */
  642. #if defined(FORCE_UPPER)
  643. #ifndef OS2
  644.   strupr(p);                            /* convert to upper case */
  645. #else /* OS2 */
  646.   if (IsFileSystemFAT(p)) strupr(p);
  647. #endif /* !OS2 */
  648. #endif
  649.   for (q = p; *q; q++)                  /* use / consistently */
  650.     if (*q == '\\')
  651.       *q = '/';
  652.  
  653.   /* If excluding, don't bother with file system */
  654.   if (exflag)
  655.   {
  656.     r = procname(p);
  657.     free((voidp *)a);
  658.     return r;
  659.   }
  660.  
  661.   /* Only name can have special matching characters */
  662.   if ((q = isshexp(p)) != NULL &&
  663.       (strrchr(q, '/') != NULL || strrchr(q, ':') != NULL))
  664.   {
  665.     free((voidp *)a);
  666.     return ZE_PARMS;
  667.   }
  668.  
  669.   /* Separate path and name into p and q */
  670.   if ((q = strrchr(p, '/')) != NULL && (q == p || q[-1] != ':'))
  671.   {
  672.     *q++ = 0;                           /* path/name -> path, name */
  673.     if (*p == 0)                        /* path is just / */
  674.       p = strcpy(v, "/.");
  675.   }
  676.   else if ((q = strrchr(p, ':')) != NULL)
  677.   {                                     /* has device and no or root path */
  678.     *q++ = 0;
  679.     p = strcat(strcpy(v, p), ":");      /* copy device as path */
  680.     if (*q == '/')                      /* -> device:/., name */
  681.     {
  682.       strcat(p, "/");
  683.       q++;
  684.     }
  685.     strcat(p, ".");
  686.   }
  687.   else                                  /* no path or device */
  688.   {
  689.     q = p;
  690.     p = strcpy(v, ".");
  691.   }
  692.  
  693.   /* Search that level for matching names */
  694.   if ((d = opend(p)) == NULL)
  695.   {
  696.     free((voidp *)a);
  697.     return ZE_MISS;
  698.   }
  699.   if ((r = strlen(p)) > 1 &&
  700.       (strcmp(p + r - 2, ":.") == 0 || strcmp(p + r - 2, "/.") == 0))
  701.     *(p + r - 1) = 0;
  702.   f = 0;
  703.   while ((e = readd(d)) != NULL)
  704.     if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e))
  705.     {
  706.       f = 1;
  707.       if (strcmp(p, ".") == 0)                  /* path is . */
  708.         procname(e);                            /* name is name */
  709.       else
  710.       {
  711.         if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
  712.         {
  713.           free((voidp *)a);
  714.           return ZE_MEM;
  715.         }
  716.         n = strcpy(n, p);
  717.         if (n[r = strlen(n) - 1] != '/' && n[r] != ':')
  718.           strcat(n, "/");
  719.         r = procname(strcat(n, e));             /* name is path/name */
  720.         free((voidp *)n);
  721.         if (r)
  722.         {
  723.           free((voidp *)a);
  724.           return r;
  725.         }
  726.       }
  727.     }
  728.   closed(d);
  729.  
  730.   /* Done */
  731.   free((voidp *)a);
  732.   return f ? ZE_OK : ZE_MISS;
  733. }
  734.  
  735. #endif /* MSDOS */
  736.  
  737.  
  738. #ifdef VMS
  739. int wild(p)
  740. char *p;                /* path/pattern to match */
  741. /* Expand the pattern based on the contents of the file system.  Return an
  742.    error code in the ZE_ class. */
  743. {
  744.   dstrm *d;             /* stream for reading directory */
  745.   char *e;              /* name found in directory */
  746.   int f;                /* true if there was a match */
  747.  
  748.   /* Search given pattern for matching names */
  749.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
  750.     return ZE_MEM;
  751.   vms_wild(p, d);       /* pattern may be more than just directory name */
  752.   f = 0;
  753.   while ((e = readd(d)) != NULL)        /* "dosmatch" is already built in */
  754.     if (procname(e) == ZE_OK)
  755.       f = 1;
  756.   closed(d);
  757.  
  758.   /* Done */
  759.   return f ? ZE_OK : ZE_MISS;
  760. }
  761. #endif /* VMS */
  762.  
  763.  
  764. char *getnam(n)
  765. char *n;                /* where to put name (must have >=FNMAX+1 bytes) */
  766. /* Read a space, \n, \r, or \t delimited name from stdin into n, and return
  767.    n.  If EOF, then return NULL.  Also, if the name read is too big, return
  768.    NULL. */
  769. {
  770.   int c;                /* last character read */
  771.   char *p;              /* pointer into name area */
  772.  
  773.   p = n;
  774.   while ((c = getchar()) == ' ' || c == '\n' || c == '\r' || c == '\t')
  775.     ;
  776.   if (c == EOF)
  777.     return NULL;
  778.   do {
  779.     if (p - n >= FNMAX)
  780.       return NULL;
  781.     *p++ = (char)c;
  782.     c = getchar();
  783.   } while (c != EOF && c != ' ' && c != '\n' && c != '\r' && c != '\t');
  784.   *p = 0;
  785.   return n;
  786. }
  787.  
  788.  
  789. struct flist far *fexpel(f)
  790. struct flist far *f;    /* entry to delete */
  791. /* Delete the entry *f in the doubly-linked found list.  Return pointer to
  792.    next entry to allow stepping through list. */
  793. {
  794.   struct flist far *t;  /* temporary variable */
  795.  
  796.   t = f->nxt;
  797.   *(f->lst) = t;                        /* point last to next, */
  798.   if (t != NULL)
  799.     t->lst = f->lst;                    /* and next to last */
  800.   if (f->name != NULL)                  /* free memory used */
  801.     free((voidp *)(f->name));
  802.   if (f->zname != NULL)
  803.     free((voidp *)(f->zname));
  804.   farfree((voidp far *)f);
  805.   fcount--;                             /* decrement count */
  806.   return t;                             /* return pointer to next */
  807. }
  808.  
  809.  
  810. local int fqcmp(a, b)
  811. voidp *a, *b;           /* pointers to pointers to found entries */
  812. /* Used by qsort() to compare entries in the found list by name. */
  813. {
  814.   return strcmp((*(struct flist far **)a)->name,
  815.                 (*(struct flist far **)b)->name);
  816. }
  817.  
  818.  
  819. local int fqcmpz(a, b)
  820. voidp *a, *b;           /* pointers to pointers to found entries */
  821. /* Used by qsort() to compare entries in the found list by zname. */
  822. {
  823.   return strcmp((*(struct flist far **)a)->zname,
  824.                 (*(struct flist far **)b)->zname);
  825. }
  826.  
  827.  
  828. local char *last(p)
  829. char *p;                /* sequence of / delimited path components */
  830. /* Return a pointer to the start of the last path component. */
  831. {
  832.   char *t;              /* temporary variable */
  833.  
  834. #ifdef VMS
  835.   if ((t = strrchr(p, ']')) != NULL)
  836. #else /* !VMS */
  837.   if ((t = strrchr(p, '/')) != NULL)
  838. #endif /* ?VMS */
  839.     return t + 1;
  840.   else
  841.     return p;
  842. }
  843.  
  844.  
  845. local char *msname(n)
  846. char *n;
  847. /* Reduce all path components to MSDOS upper case 8.3 style names.  Probably
  848.    should also check for invalid characters, but I don't know which ones
  849.    those are. */
  850. {
  851.   int c;                /* current character */
  852.   int f;                /* characters in current component */
  853.   char *p;              /* source pointer */
  854.   char *q;              /* destination pointer */
  855.  
  856.   p = q = n;
  857.   f = 0;
  858.   while ((c = *p++) != 0)
  859.     if (c == '/')
  860.     {
  861.       *q++ = (char)c;
  862.       f = 0;                            /* new component */
  863.     }
  864.     else if (c == '.')
  865.       if (f < 9)
  866.       {
  867.         *q++ = (char)c;
  868.         f = 9;                          /* now in file type */
  869.       }
  870.       else
  871.         f = 12;                         /* now just excess characters */
  872.     else
  873.       if (f < 12 && f != 8)
  874.       {
  875.         *q++ = (char)(to_up(c));
  876.         f++;                            /* do until end of name or type */
  877.       }
  878.   *q = 0;
  879.   return n;
  880. }
  881.  
  882.  
  883. #ifdef VMS
  884. local char *strlower(s)
  885. char *s;                /* string to convert */
  886. /* Convert all uppercase letters to lowercase in string s */
  887. {
  888.   char *p;              /* scans string */
  889.  
  890.   for (p = s; *p; p++)
  891.     if (*p >= 'A' && *p <= 'Z')
  892.       *p += 'a' - 'A';
  893.   return s;
  894. }
  895.  
  896. local char *strupper(s)
  897. char *s;                /* string to convert */
  898. /* Convert all lowercase letters to uppercase in string s */
  899. {
  900.   char *p;              /* scans string */
  901.  
  902.   for (p = s; *p; p++)
  903.     if (*p >= 'a' && *p <= 'z')
  904.       *p -= 'a' - 'A';
  905.   return s;
  906. }
  907. #endif /* VMS */
  908.  
  909. local char *ex2in(x, pdosflag)
  910. char *x;                /* external file name */
  911. int *pdosflag;          /* output: force MSDOS file attributes? */
  912. /* Convert the external file name to a zip file name, returning the malloc'ed
  913.    string or NULL if not enough memory. */
  914. {
  915.   char *n;              /* internal file name (malloc'ed) */
  916.   char *t;              /* shortened name */
  917.   int dosflag;
  918.  
  919. #ifdef OS2
  920.   dosflag = dosify || IsFileSystemFAT(x);
  921.   if ( !dosify && use_longname_ea && (t = GetLongPathEA(x)) != NULL )
  922.   {
  923.     x = t;
  924.     dosflag = 0;
  925.   }
  926. #else
  927. # ifdef MSDOS
  928.   dosflag = 1;
  929. # else /* !MSDOS */
  930.   dosflag = dosify; /* default for non-DOS and non-OS/2 */
  931. # endif /* MSDOS */
  932. #endif /* OS2 */
  933.  
  934.   /* Find starting point in name before doing malloc */
  935. #ifdef MSDOS                            /* msdos */
  936.   t = *x && *(x + 1) == ':' ? x + 2 : x;
  937.   while (*t == '/' || *t == '\\')
  938.     t++;
  939. #else /* !MSDOS */
  940. #  ifdef VMS                            /* vms */
  941.   t = x;
  942.   if ((n = strrchr(t, ':')) != NULL)
  943.     t = n + 1;
  944.   if (*t == '[' && (n = strrchr(t, ']')) != NULL)
  945.     if ((x = strchr(t, '.')) != NULL && x < n)
  946.       t = x + 1;
  947.     else
  948.       t = n + 1;
  949. #  else /* !VMS */                      /* unix */
  950.   for (t = x; *t == '/'; t++)
  951.     ;
  952. #  endif /* ?VMS */
  953. #endif /* ?MSDOS */
  954.  
  955.   /* Make changes, if any, to the copied name (leave original intact) */
  956. #ifdef MSDOS
  957.   for (n = t; *n; n++)
  958.     if (*n == '\\')
  959.       *n = '/';
  960. #endif /* MSDOS */
  961.  
  962.   if (!pathput)
  963.     t = last(t);
  964.  
  965.   /* Malloc space for internal name and copy it */
  966.   if ((n = malloc(strlen(t) + 1)) == NULL)
  967.     return NULL;
  968.   strcpy(n, t);
  969.  
  970. #ifdef VMS
  971.   if ((t = strrchr(n, ']')) != NULL)
  972.   {
  973.     *t = '/';
  974.     while (--t > n)
  975.       if (*t == '.')
  976.         *t = '/';
  977.   }
  978.  
  979.   /* Fix from Greg Roelofs: */
  980.   /* Get current working directory and strip from n (t now = n) */
  981.   {
  982.     char cwd[256], *p, *q;
  983.     int c;
  984.  
  985.     if (getcwd(cwd, 256) && ((p = strchr(cwd, '.')) != NULL))
  986.     {
  987.       ++p;
  988.       if ((q = strrchr(p, ']')) != NULL)
  989.       {
  990.         *q = '/';
  991.         while (--q > p)
  992.           if (*q == '.')
  993.             *q = '/';
  994.         /* strip bogus path parts from n */
  995.         if (strncmp(n, p, (c=strlen(p))) == 0)
  996.         {
  997.           q = n + c;
  998.           while (*t++ = *q++)
  999.             ;
  1000.         }
  1001.       }
  1002.     }
  1003.   }
  1004.   strlower(n);
  1005.   if (!vmsver)
  1006.     if ((t = strrchr(n, ';')) != NULL)
  1007.       *t = 0;
  1008.  
  1009.   if( (t = strrchr(n, '.')) != NULL )
  1010.   {
  1011.     if( t[1] == 0 )               /* "filename." -> "filename" */
  1012.       *t = 0;
  1013.     else if( t[1] == ';' )        /* "filename.;vvv" -> "filename;vvv" */
  1014.     {
  1015.       char *f;
  1016.       for( f=t+1; *t++ = *f++; )
  1017.         ;
  1018.     }
  1019.   }
  1020. #endif /* VMS */
  1021.   if (dosify)
  1022.     msname(n);
  1023. #if defined(MSDOS) && !defined(OS2) && !defined(FORCE_UPPER)
  1024.   else
  1025.     strlwr(n);
  1026. #endif
  1027.   /* Returned malloc'ed name */
  1028.   if (pdosflag) 
  1029.     *pdosflag = dosflag;
  1030.   return n;
  1031. }
  1032.  
  1033.  
  1034. char *in2ex(n)
  1035. char *n;                /* internal file name */
  1036. /* Convert the zip file name to an external file name, returning the malloc'ed
  1037.    string or NULL if not enough memory. */
  1038. {
  1039.   char *x;              /* external file name */
  1040. #ifdef VMS
  1041.   char *t;              /* scans name */
  1042.  
  1043.   if ((t = strrchr(n, '/')) == NULL)
  1044. #endif /* VMS */
  1045.   {
  1046.     if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
  1047.       return NULL;
  1048.     strcpy(x, n);
  1049.   }
  1050. #ifdef VMS
  1051.   else
  1052.   {
  1053.     if ((x = malloc(strlen(n) + 3 + PAD)) == NULL)
  1054.       return NULL;
  1055.     strcpy(x, "[.");
  1056.     strcpy(x + 2, n);
  1057.     *(t = x + 2 + (t - n)) = ']';
  1058.     while (--t > x)
  1059.       if (*t == '/')
  1060.         *t = '.';
  1061.   }
  1062.   strupper(x);
  1063. #endif /* VMS */
  1064. #ifdef OS2
  1065.   if ( !IsFileNameValid(x) )
  1066.     ChangeNameForFAT(x);
  1067. #endif /* !OS2 */
  1068. #if defined(FORCE_UPPER) && defined(MSDOS)
  1069.   /* Don't convert to upper case, causes wrong warnings. Keep the
  1070.    * name as it was before in the old zip file.
  1071.    */
  1072.   strupr(x);
  1073. #endif
  1074.   return x;
  1075. }
  1076.  
  1077.  
  1078. int exclude()
  1079. /* Change from including to excluding names when procname() called.  Return
  1080.    an error code in the ZE_ class. */
  1081. {
  1082.   struct flist far *f;          /* steps through found linked list */
  1083.   extent j;                     /* index for s */
  1084.   struct flist far **s;         /* sorted table */
  1085.  
  1086.   /* sort found list, remove duplicates */
  1087.   if (fcount)
  1088.   {
  1089.     if ((s = (struct flist far **)malloc(
  1090.          fcount * sizeof(struct flist far *))) == NULL)
  1091.       return ZE_MEM;
  1092.     for (j = 0, f = found; f != NULL; f = f->nxt)
  1093.       s[j++] = f;
  1094.     qsort((char *)s, fcount, sizeof(struct flist far *), fqcmp);
  1095.     for (j = fcount - 1; j > 0; j--)
  1096.       if (strcmp(s[j - 1]->name, s[j]->name) == 0)
  1097.         fexpel(s[j]);           /* fexpel() changes fcount */
  1098.     qsort((char *)s, fcount, sizeof(struct flist far *), fqcmpz);
  1099.     for (j = 1; j < fcount; j++)
  1100.       if (strcmp(s[j - 1]->zname, s[j]->zname) == 0)
  1101.       {
  1102.         warn("name in zip file repeated: ", s[j]->zname);
  1103.         warn("  first full name: ", s[j - 1]->name);
  1104.         warn(" second full name: ", s[j]->name);
  1105.         return ZE_PARMS;
  1106.       }
  1107.     free((voidp *)s);
  1108.   }
  1109.   exflag = 1;
  1110.   return ZE_OK;
  1111. }
  1112.  
  1113.  
  1114. local int newname(n)
  1115. char *n;                /* name to add (or exclude) */
  1116. /* Add (or exclude) a name that is not in the zip file.  Return an error
  1117.    code in the ZE_ class. */
  1118. {
  1119.   char *m;
  1120.   struct flist far *f;  /* where in found, or new found entry */
  1121.   struct zlist far *z;  /* where in zfiles (if found) */
  1122.   int dosflag;
  1123.  
  1124.   /* Search for name in zip file.  If there, mark it, else add to
  1125.      list of new names to do (or remove from that list). */
  1126.   if ((m = ex2in(n, &dosflag)) == NULL)
  1127.     return ZE_MEM;
  1128.   if ((z = zsearch(m)) != NULL)
  1129.     if (exflag)
  1130.     {
  1131.       z->mark = 0;
  1132.       free((voidp *)m);
  1133.       if (verbose)
  1134.         printf("zip diagnostic: excluding %s\n", z->name);
  1135.     }
  1136.     else
  1137.     {
  1138.       free((voidp *)(z->name));
  1139.       free((voidp *)(z->zname));
  1140.       if ((z->name = malloc(strlen(n) + 1 + PAD)) == NULL)
  1141.         return ZE_MEM;
  1142.       strcpy(z->name, n);
  1143.       z->zname = m;
  1144.       z->mark = 1;
  1145.       z->dosflag = dosflag;
  1146.       if (verbose)
  1147.         printf("zip diagnostic: including %s\n", z->name);
  1148.     }
  1149.   else
  1150.     if (exflag)
  1151.     {
  1152.       /* search list for name--if there, remove it */
  1153.       for (f = found; f != NULL; f = f->nxt)
  1154.         if (namecmp(n, f->name) == 0)
  1155.         {
  1156.           fexpel(f);
  1157.           break;
  1158.         }
  1159.       free((voidp *)m);
  1160.     }
  1161.     else
  1162.     {
  1163.       /* allocate space and add to list */
  1164.       if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
  1165.           (f->name = malloc(strlen(n) + 1 + PAD)) == NULL)
  1166.       {
  1167.         if (f != NULL)
  1168.           farfree((voidp far *)f);
  1169.         return ZE_MEM;
  1170.       }
  1171.       strcpy(f->name, n);
  1172.       f->zname = m;
  1173.       f->dosflag = dosflag;
  1174.       *fnxt = f;
  1175.       f->lst = fnxt;
  1176.       f->nxt = NULL;
  1177.       fnxt = &f->nxt;
  1178.       fcount++;
  1179.     }
  1180.   return ZE_OK;
  1181. }
  1182.  
  1183.  
  1184. int procname(n)
  1185. char *n;                /* name to process */
  1186. /* Process a name or sh expression to operate on (or exclude).  Return
  1187.    an error code in the ZE_ class. */
  1188. {
  1189.   char *a;              /* path and name for recursion */
  1190.   dstrm *d;             /* directory stream from opend() */
  1191.   char *e;              /* pointer to name from readd() */
  1192.   struct flist far *f;  /* steps through found list */
  1193.   int m;                /* matched flag */
  1194.   char *p;              /* path for recursion */
  1195.   struct stat s;        /* result of stat() */
  1196.   struct zlist far *z;  /* steps through zfiles list */
  1197.  
  1198.   if (strcmp(n, "-") == 0)   /* if compressing stdin */
  1199.     return newname(n);
  1200.   else if (
  1201. #ifdef S_IFLNK          /* if symbolic links exist ... */
  1202.       linkput ? lstat(n, &s) :
  1203. #endif /* S_IFLNK */
  1204.       SSTAT(n, &s)
  1205. #if defined(__TURBOC__) || defined(VMS) || defined(__GO32__)
  1206.        /* Borland and VMS C bug: stat() succeeds on wild card names! */
  1207.       || isshexp(n)
  1208. #endif
  1209.      )
  1210.   {
  1211.     /* Not a file or directory--search for shell expression in zip file */
  1212.     p = ex2in(n, NULL);         /* shouldn't affect matching chars */
  1213.     m = 1;
  1214.     for (z = zfiles; z != NULL; z = z->nxt)
  1215.       if (MATCH(p, z->zname))
  1216.       {
  1217.         z->mark = !exflag;
  1218.         if (verbose)
  1219.           printf("zip diagnostic: %scluding %s\n",
  1220.                  exflag ? "ex" : "in", z->name);
  1221.         m = 0;
  1222.       }
  1223.     /* If excluding, also search for expression in found list */
  1224.     if (exflag)
  1225.     {
  1226.       for (f = found; f != NULL;)
  1227.         if (MATCH(p, f->zname))
  1228.         {
  1229.           f = fexpel(f);
  1230.           m = 0;
  1231.         }
  1232.         else
  1233.           f = f->nxt;
  1234.     }
  1235.     free((voidp *)p);
  1236.     if (m)
  1237.       return ZE_MISS;           /* no match */
  1238.   }
  1239.   else
  1240.   {
  1241.     /* Live name--use if file, recurse if directory */
  1242. #if defined(FORCE_UPPER) && defined(MSDOS)
  1243. # ifndef OS2
  1244.     strupr(n);                  /* convert to upper case */
  1245. # else /* OS2 */
  1246.     if (IsFileSystemFAT(n)) strupr(n);
  1247. # endif /* !OS2 */
  1248. #endif
  1249.  
  1250. #ifdef MSDOS
  1251.     for (p = n; *p; p++)          /* use / consistently */
  1252.       if (*p == '\\')
  1253.         *p = '/';
  1254. #endif /* MSDOS */
  1255.     if ((s.st_mode & S_IFDIR) == 0)
  1256.     {
  1257.       /* add or remove name of file */
  1258.         if ((m = newname(n)) != ZE_OK)
  1259.           return m;
  1260.     } else {
  1261.         /* recurse into directory */
  1262.         if (recurse && (d = opend(n)) != NULL)
  1263.         {
  1264. #ifdef VMS
  1265.           while ((e = readd(d)) != NULL)
  1266.             if ((m = procname(e)) != ZE_OK)     /* recurse on name */
  1267.             {
  1268.               /* want to just set warning error and continue */
  1269.               closed(d);
  1270.               return m;
  1271.             }
  1272. #else /* !VMS */
  1273.           if ((p = malloc(strlen(n)+2)) == NULL)
  1274.             return ZE_MEM;
  1275.           if (strcmp(n, ".") == 0)
  1276.             *p = 0; /* avoid "./" prefix and do not create zip entry */
  1277.           else
  1278.           {
  1279.             strcpy(p, n);
  1280.             a = p + strlen(p);
  1281.             if (a[-1] != '/')
  1282.               strcpy(a, "/");
  1283.             if ((m = newname(p)) != ZE_OK)
  1284.               return m;
  1285.           }
  1286.           while ((e = readd(d)) != NULL)
  1287.             if (strcmp(e, ".") && strcmp(e, ".."))
  1288.             {
  1289.               if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
  1290.               {
  1291.                 free((voidp *)p);
  1292.                 closed(d);
  1293.                 return ZE_MEM;
  1294.               }
  1295.               strcat(strcpy(a, p), e);
  1296.               if ((m = procname(a)) != ZE_OK)   /* recurse on name */
  1297.               {
  1298.                 free((voidp *)a);  free((voidp *)p);
  1299.                 closed(d);
  1300.                 return m;
  1301.               }
  1302.               free((voidp *)a);
  1303.             }
  1304.           free((voidp *)p);
  1305. #endif /* ?VMS */
  1306.           closed(d);
  1307.         }
  1308.       }
  1309.     }
  1310.   return ZE_OK;
  1311. }
  1312.  
  1313.  
  1314. #if !defined(CRAY) && !defined(__TURBOC__) && !defined(OS2) /* and ... */
  1315. #if !defined( __GO32__)
  1316.  
  1317. local int cmptime(p, q)
  1318. struct tm *p, *q;       /* times to compare */
  1319. /* Return negative if time p is before time q, positive if after, and
  1320.    zero if the same */
  1321. {
  1322.   int r;                /* temporary variable */
  1323.  
  1324.   if (p == NULL)
  1325.     return -1;
  1326.   else if ((r = p->tm_year - q->tm_year) != 0)
  1327.     return r;
  1328.   else if ((r = p->tm_mon - q->tm_mon) != 0)
  1329.     return r;
  1330.   else if ((r = p->tm_mday - q->tm_mday) != 0)
  1331.     return r;
  1332.   else if ((r = p->tm_hour - q->tm_hour) != 0)
  1333.     return r;
  1334.   else if ((r = p->tm_min - q->tm_min) != 0)
  1335.     return r;
  1336.   else
  1337.     return p->tm_sec - q->tm_sec;
  1338. }
  1339.  
  1340.  
  1341. local time_t invlocal(t)
  1342. struct tm *t;           /* time to convert */
  1343. /* Find inverse of localtime() using bisection.  This routine assumes that
  1344.    time_t is an integer type, either signed or unsigned.  The expectation
  1345.    is that sometime before the year 2038, time_t will be made a 64-bit
  1346.    integer, and this routine will still work. */
  1347. {
  1348.   time_t i;             /* midpoint of current root range */
  1349.   time_t l;             /* lower end of root range */
  1350.   time_t u;             /* upper end of root range */
  1351.  
  1352.   /* Bracket the root [0,largest time_t].  Note: if time_t is a 32-bit signed
  1353.      integer, then the upper bound is GMT 1/19/2038 03:14:07, after which all
  1354.      the Unix systems in the world come to a grinding halt.  Either that, or
  1355.      all those systems will suddenly find themselves transported to December
  1356.      of 1901 ... */
  1357.   l = 0;
  1358.   u = 1;
  1359.   while (u < (u << 1))
  1360.     u = (u << 1) + 1;
  1361.  
  1362.   /* Find the root */
  1363.   while (u - l > 1)
  1364.   {
  1365.     i = l + ((u - l) >> 1);
  1366.     if (cmptime(localtime(&i), t) <= 0)
  1367.       l = i;
  1368.     else
  1369.       u = i;
  1370.   }
  1371.   return l;
  1372. }
  1373. #endif
  1374. #endif
  1375.  
  1376.  
  1377. void stamp(f, d)
  1378. char *f;                /* name of file to change */
  1379. ulg d;                  /* dos-style time to change it to */
  1380. /* Set last updated and accessed time of file f to the DOS time d. */
  1381. {
  1382. #if defined(MACOS)
  1383.   warn("timestamp not implemented yet", "");
  1384. #else
  1385. #ifdef __TURBOC__
  1386.   int h;                /* file handle */
  1387.  
  1388.   if ((h = open(f, 0)) != -1)
  1389.   {
  1390. #ifdef ATARI_ST
  1391.     d = ( d >> 16 ) | ( d << 16 );
  1392. #endif
  1393.     setftime(h, (struct ftime *)&d);
  1394.     close(h);
  1395.   }
  1396. #else /* !__TURBOC__ */
  1397. #ifdef VMS
  1398.   int tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year;
  1399.   char timbuf[24];
  1400.   static char *month[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
  1401.                           "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
  1402.   struct VMStimbuf {
  1403.       char *actime;           /* VMS revision date, ASCII format */
  1404.       char *modtime;          /* VMS creation date, ASCII format */
  1405.   } ascii_times = {timbuf, timbuf};
  1406.  
  1407.   /* Convert DOS time to ASCII format for VMSmunch */
  1408.   tm_sec = (int)(d << 1) & 0x3e;
  1409.   tm_min = (int)(d >> 5) & 0x3f;
  1410.   tm_hour = (int)(d >> 11) & 0x1f;
  1411.   tm_mday = (int)(d >> 16) & 0x1f;
  1412.   tm_mon = ((int)(d >> 21) & 0xf) - 1;
  1413.   tm_year = ((int)(d >> 25) & 0x7f) + 1980;
  1414.   sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", tm_mday, month[tm_mon],
  1415.     tm_year, tm_hour, tm_min, tm_sec);
  1416.  
  1417.   /* Set updated and accessed times of f */
  1418.   if (VMSmunch(f, SET_TIMES, &ascii_times) != RMS$_NMF)
  1419.     warn("can't set zipfile time: ", f);
  1420.  
  1421. #else /* !VMS */
  1422. #ifdef OS2
  1423.   SetFileTime(f, d);
  1424. #else /* !OS2 */
  1425.   struct tm t;          /* argument for mktime() or invlocal() */
  1426.   time_t u[2];          /* argument for utime() */
  1427. #ifndef __GO32__
  1428.   extern time_t mktime OF((struct tm *));
  1429. #endif
  1430.  
  1431.   /* Convert DOS time to time_t format in u[0] and u[1] */
  1432.   t.tm_sec = (int)(d << 1) & 0x3e;
  1433.   t.tm_min = (int)(d >> 5) & 0x3f;
  1434.   t.tm_hour = (int)(d >> 11) & 0x1f;
  1435.   t.tm_mday = (int)(d >> 16) & 0x1f;
  1436.   t.tm_mon = ((int)(d >> 21) & 0xf) - 1;
  1437.   t.tm_year = ((int)(d >> 25) & 0x7f) + 80;
  1438. #if defined(MSDOS) || defined(OS2) || defined(CRAY)
  1439.   /* mktime() is more reliable than invlocal() because the time range is
  1440.    * wider on MSDOS than on Unix; required for Cray because invlocal assumes
  1441.    * 32-bit ints
  1442.    */
  1443.   u[0] = u[1] = mktime(&t);
  1444. #else
  1445.   u[0] = u[1] = invlocal(&t);
  1446. #endif
  1447.  
  1448.   /* Set updated and accessed times of f */
  1449.   utime(f, u);
  1450. #endif /* ?OS2 */
  1451. #endif /* ?VMS */
  1452. #endif /* ?__TURBOC__ */
  1453. #endif /* ?MACOS */
  1454. }
  1455.  
  1456.  
  1457. local void inctime(s)
  1458. struct tm *s;           /* time to increment in place */
  1459. /* Increment the time structure *s by one second, return the result in
  1460.    place. */
  1461. {
  1462.   int y;                /* temporary variable */
  1463.  
  1464.   /* days in each month, except for February */
  1465.   static int days[] = {31,0,31,30,31,30,31,31,30,31,30,31};
  1466.  
  1467.   /* Set days in February from year (1900 is a leap year, 2000 is not) */
  1468.   y = s->tm_year + 1900;
  1469.   days[1] = y % 4 == 0 && (y % 100 != 0 || y % 400 == 0) ? 29 : 28;
  1470.  
  1471.   /* Increment time with carry */
  1472.   if (s->tm_sec != 59)
  1473.     s->tm_sec++;
  1474.   else if (s->tm_sec = 0, s->tm_min != 59)
  1475.     s->tm_min++;
  1476.   else if (s->tm_min = 0, s->tm_hour != 23)
  1477.     s->tm_hour++;
  1478.   else if (s->tm_hour = 0, s->tm_mday != days[s->tm_mon])
  1479.     s->tm_mday++;
  1480.   else if (s->tm_mday = 1, s->tm_mon != 11)
  1481.     s->tm_mon++;
  1482.   else
  1483.   {
  1484.     s->tm_mon = 0;
  1485.     s->tm_year++;
  1486.   }
  1487. }
  1488.  
  1489.  
  1490. ulg dostime(y, n, d, h, m, s)
  1491. int y;                  /* year */
  1492. int n;                  /* month */
  1493. int d;                  /* day */
  1494. int h;                  /* hour */
  1495. int m;                  /* minute */
  1496. int s;                  /* second */
  1497. /* Convert the date y/n/d and time h:m:s to a four byte DOS date and
  1498.    time (date in high two bytes, time in low two bytes allowing magnitude
  1499.    comparison). */
  1500. {
  1501.   return y < 1980 ? dostime(1980, 1, 1, 0, 0, 0) :
  1502.         (((ulg)y - 1980) << 25) | ((ulg)n << 21) | ((ulg)d << 16) |
  1503.         ((ulg)h << 11) | ((ulg)m << 5) | ((ulg)s >> 1);
  1504. }
  1505.  
  1506.  
  1507. local ulg unix2dostime(t)
  1508. statime *t;             /* unix time to convert */
  1509. /* Return the Unix time t in DOS format, rounded up to the next two
  1510.    second boundary. */
  1511. {
  1512.   struct tm *s;         /* result of localtime() */
  1513.  
  1514.   s = localtime(t);             /* Use local time since MSDOS does */
  1515.   inctime(s);                   /* Add one second to round up */
  1516.   return dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday,
  1517.                  s->tm_hour, s->tm_min, s->tm_sec);
  1518. }
  1519.  
  1520.  
  1521. ulg filetime(f, a, n)
  1522. char *f;                /* name of file to get info on */
  1523. ulg *a;                 /* return value: file attributes */
  1524. long *n;                /* return value: file size */
  1525. /* If file *f does not exist, return 0.  Else, return the file's last
  1526.    modified date and time as an MSDOS date and time.  The date and
  1527.    time is returned in a long with the date most significant to allow
  1528.    unsigned integer comparison of absolute times.  Also, if a is not
  1529.    a NULL pointer, store the file attributes there, with the high two
  1530.    bytes being the Unix attributes, and the low byte being a mapping
  1531.    of that to DOS attributes.  If n is not NULL, store the file size
  1532.    there.
  1533.    If f is "-", use standard input as the file. If f is a device, return
  1534.    a file size of -1 */
  1535. {
  1536.   struct stat s;        /* results of stat() */
  1537.   char name[FNMAX];
  1538.   int len = strlen(f);
  1539.  
  1540.   strcpy(name, f);
  1541.   if (name[len - 1] == '/')
  1542.     name[len - 1] = 0; 
  1543.   /* not all systems allow stat'ing a file with / appended */
  1544.  
  1545.   if (strcmp(f, "-") == 0) {
  1546.     if (fstat(fileno(stdin), &s) != 0)
  1547.       error("fstat(stdin)");
  1548.   } else if ((
  1549. #ifdef S_IFLNK
  1550.              linkput ? lstat(name, &s) :
  1551. #endif
  1552.              SSTAT(name, &s)) != 0)
  1553.              /* Accept about any file kind including directories
  1554.               * (stored with trailing / with -r option)
  1555.               */
  1556.     return 0;
  1557.  
  1558.   if (a != NULL)
  1559. #ifdef OS2
  1560.     *a = (s.st_mode << 16) | GetFileMode(name);
  1561. #else
  1562.     *a = (s.st_mode << 16) | !(s.st_mode & S_IWRITE);
  1563. #endif
  1564.   if (n != NULL)
  1565.     *n = (s.st_mode & S_IFREG) == 0 ? -1L : s.st_size;
  1566.  
  1567. #ifdef OS2
  1568.   return GetFileTime(name);
  1569. #else /* !OS2 */
  1570. #  ifdef VMS
  1571.      return unix2dostime(&s.st_ctime);   /* Use creation time in VMS */
  1572. #  else /* !VMS */
  1573. #    ifdef ATARI_ST
  1574.        return s.st_mtime; /* Turbo C doesn't use UNIX times */
  1575. #    else
  1576.        return unix2dostime(&s.st_mtime);
  1577. #    endif
  1578. #  endif /* ?VMS */
  1579. #endif /* ?OS2 */
  1580. }
  1581.  
  1582.  
  1583. int issymlnk(a)
  1584. ulg a;                  /* Attributes returned by filetime() */
  1585. /* Return true if the attributes are those of a symbolic link */
  1586. {
  1587. #ifdef S_IFLNK
  1588.   return ((a >> 16) & S_IFMT) == S_IFLNK;
  1589. #else /* !S_IFLNK */
  1590.   return (int)a & 0;    /* avoid warning on unused parameter */
  1591. #endif /* ?S_IFLNK */
  1592. }
  1593.  
  1594.  
  1595. int deletedir(d)
  1596. char *d;                /* directory to delete */
  1597. /* Delete the directory *d if it is empty, do nothing otherwise.
  1598.    Return the result of rmdir(), delete(), or system().
  1599.  */
  1600. {
  1601. #ifdef MACOS
  1602.   warn("deletedir not implemented yet", "");
  1603.   return 127;
  1604. #else
  1605. #ifdef RMDIR
  1606.   /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
  1607.   int r, len;
  1608.   char *s;              /* malloc'd string for system command */
  1609.  
  1610.   len = strlen(d);
  1611.   if ((s = malloc(len + 34)) == NULL)
  1612.     return 127;
  1613.  
  1614. #ifdef VMS
  1615.   {
  1616.     char *c;            /* pointer into VMS path */
  1617.     /* convert "DEV:[DIR.SUB1.SUB2]" form to "DEV:[DIR.SUB1]SUB2.DIR;0" */
  1618.     strcat(strcpy(s, "set prot=(o:rwed) "), d);   /* d starts at s+18 */
  1619.     if (*(c = s+17+len) != ']')
  1620.     {
  1621.       free(s);
  1622.       return 127;
  1623.     }
  1624.     strcpy(c, ".DIR;0");        /* 0 translates to highest version */
  1625.     while (--c > s+18  &&  *c != '.'  &&  *c != '[') ;
  1626.     if (c == s+18)
  1627.     {
  1628.       free(s);
  1629.       return 127;
  1630.     }
  1631.     if (*c == '.')
  1632.       *c = ']';
  1633.     else if (*--c == ']')  /* presumably of form "DEV:[DIR.SUB1.][SUB2]" */
  1634.     {                      /* (possible to have "DEV:[DIR.SUB1.][][SUB2]"?) */
  1635.       char *b = c + 2;
  1636.       c[-1] = ']';
  1637.       while (*c++ = *b++) ;
  1638.     }
  1639.     else        /* must have reached device name:  can't delete top level */
  1640.     {
  1641.       free(s);
  1642.       return 127;
  1643.     }
  1644.   }
  1645.   /* unprotect directory and delete it as a file.  May fail if exists 
  1646.      normal file "foo.dir" on top of directory "foo.dir" */
  1647.   system(s);
  1648.   r = delete(s+18);
  1649. #else /* !VMS */
  1650.   sprintf(s, "IFS=\" \t\n\" /bin/rmdir %s 2>/dev/null", d);
  1651.   r = system(s);
  1652. #endif /* ?VMS */
  1653.   free(s);
  1654.   return r;
  1655. #else /* !RMDIR */
  1656.   return rmdir(d);
  1657. #endif /* ?RMDIR */
  1658. #endif /* ?MACOS */
  1659. }
  1660.  
  1661.  
  1662. #endif /* !UTIL */
  1663.  
  1664. int destroy(f)
  1665. char *f;                /* file to delete */
  1666. /* Delete the file *f, returning non-zero on failure. */
  1667. {
  1668.   return unlink(f);
  1669. }
  1670.  
  1671.  
  1672. int replace(d, s)
  1673. char *d, *s;            /* destination and source file names */
  1674. /* Replace file *d by file *s, removing the old *s.  Return an error code
  1675.    in the ZE_ class. */
  1676. {
  1677.   struct stat t;        /* results of stat() */
  1678.  
  1679.   if (SSTAT(d, &t) == 0 && unlink(d))
  1680.     return ZE_CREAT;                    /* Can't erase zip file--give up */
  1681.   if (link(s, d))                       /* Just move s on top of d */
  1682. #if !defined(VMS) && !defined(ATARI_ST)
  1683.     /* For VMS & ATARI assume failure is EXDEV */
  1684.     if (errno != EXDEV
  1685. #  ifdef ENOTSAM
  1686.        && errno != ENOTSAM /* Used at least on Turbo C */
  1687. #  endif
  1688.         ) return ZE_CREAT;
  1689.     else
  1690. #endif
  1691.     {
  1692.       FILE *f, *g;      /* source and destination files */
  1693.       int r;            /* temporary variable */
  1694.  
  1695.       if ((f = fopen(s, FOPR)) == NULL) {
  1696.         fprintf(stderr," replace: can't open %s\n", s);
  1697.         return ZE_TEMP;
  1698.       }
  1699.       if ((g = fopen(d, FOPW)) == NULL)
  1700.       {
  1701.         fclose(f);
  1702.         return ZE_CREAT;
  1703.       }
  1704.       r = fcopy(f, g, (ulg)-1L);
  1705.       fclose(f);
  1706.       if (fclose(g) || r != ZE_OK)
  1707.       {
  1708.         unlink(d);
  1709.         return r ? (r == ZE_TEMP ? ZE_WRITE : r) : ZE_WRITE;
  1710.       }
  1711. #ifdef VMS /* only delete if rename failed:  previous version may exist */
  1712.       unlink(s);
  1713.     }
  1714. #else /* !VMS */
  1715.     }
  1716.   unlink(s);
  1717. #endif /* !VMS */
  1718.   return ZE_OK;
  1719. }
  1720.  
  1721.  
  1722. int getfileattr(f)
  1723. char *f;                /* file path */
  1724. /* Return the file attributes for file f or 0 if failure */
  1725. {
  1726.   struct stat s;
  1727.  
  1728.   return SSTAT(f, &s) == 0 ? s.st_mode : 0;
  1729. }
  1730.  
  1731.  
  1732. int setfileattr(f, a)
  1733. char *f;                /* file path */
  1734. int a;                  /* attributes returned by getfileattr() */
  1735. /* Give the file f the attributes a, return non-zero on failure */
  1736. {
  1737. #if defined (VMS) || defined(MACOS)
  1738.   return 0;
  1739. #else /* !VMS */
  1740.   return chmod(f, a);
  1741. #endif /* ?VMS */
  1742. }
  1743.  
  1744.  
  1745. #ifdef NO_MKTEMP
  1746.  
  1747. char *tempname(zip)
  1748.   char *zip;              /* path name of zip file to generate temp name for */
  1749.  
  1750. /* Return a temporary file name in its own malloc'ed space.
  1751.  * This function might accidentally destroy an existing file
  1752.  * with extension .$z$ . Use mktemp below if you have it on your system.
  1753.  */
  1754. {
  1755.   char *p;              /* temporary pointer */
  1756.   char *t;              /* malloc'ed space for name */
  1757.  
  1758.   if ((t = malloc(strlen(zip)+5)) == NULL)
  1759.     return NULL;
  1760.   strcpy(t, zip);
  1761.   if ((p = strrchr(t, '.')) != NULL &&
  1762.       (!strncmp(p, ".zip", 4) || !strncmp(p, ".ZIP", 4)))
  1763.       /* strncmp to avoid problems with VMS ';' */
  1764.     strcpy(p, ".$z$");
  1765.   else
  1766.     strcat(t, ".$z$");
  1767.  
  1768.   return t;
  1769. }
  1770. #else /* !NO_MKTEMP */
  1771.  
  1772. char *tempname(zip)
  1773.   char *zip;              /* path name of zip file to generate temp name for */
  1774.  
  1775. /* Return a temporary file name in its own malloc'ed space, using tempath. */
  1776. {
  1777.   char *t = zip;   /* malloc'ed space for name (use zip to avoid warning) */
  1778.  
  1779.   if (tempath != NULL)
  1780.   {
  1781.     if ((t = malloc(strlen(tempath)+10)) == NULL)
  1782.       return NULL;
  1783.     strcpy(t, tempath);
  1784. #ifndef VMS
  1785.     if (t[strlen(t)-1] != '/')
  1786.       strcat(t, "/");
  1787. #endif
  1788.   }
  1789.   else
  1790.   {
  1791.     if ((t = malloc(9)) == NULL)
  1792.       return NULL;
  1793.     *t = 0;
  1794.   }
  1795.   strcat(t, "_ZXXXXXX");
  1796.   return mktemp(t);
  1797. }
  1798.  
  1799. #endif /* NO_MKTEMP */
  1800.  
  1801.  
  1802. int fcopy(f, g, n)
  1803. FILE *f, *g;            /* source and destination files */
  1804. ulg n;                  /* number of bytes to copy or -1 for all */
  1805. /* Copy n bytes from file *f to file *g, or until EOF if n == -1.  Return
  1806.    an error code in the ZE_ class. */
  1807. {
  1808.   char *b;              /* malloc'ed buffer for copying */
  1809.   extent k;             /* result of fread() */
  1810.   ulg m;                /* bytes copied so far */
  1811.  
  1812.   if ((b = malloc(CBSZ)) == NULL)
  1813.     return ZE_MEM;
  1814.   m = 0;
  1815.   while (n == -1L || m < n)
  1816.   {
  1817.     if ((k = fread(b, 1, n == -1 ?
  1818.                    CBSZ : (n - m < CBSZ ? (extent)(n - m) : CBSZ), f)) == 0)
  1819.       if (ferror(f))
  1820.       {
  1821.         free((voidp *)b);
  1822.         return ZE_READ;
  1823.       }
  1824.       else
  1825.         break;
  1826.     if (fwrite(b, 1, k, g) != k)
  1827.     {
  1828.       free((voidp *)b);
  1829.       fprintf(stderr," fcopy: write error\n");
  1830.       return ZE_TEMP;
  1831.     }
  1832.     m += k;
  1833.   }
  1834.   free((voidp *)b);
  1835.   return ZE_OK;
  1836. }
  1837.  
  1838.  
  1839. #ifdef CRYPT
  1840.  
  1841. #ifndef MSDOS
  1842.  
  1843. #ifdef VMS
  1844.  
  1845. int echo(opt)
  1846.     int opt;
  1847. {
  1848. /*---------------------------------------------------------------------------
  1849.     Based on VMSmunch.c, which in turn was based on Joe Meadows' file.c code.
  1850.   ---------------------------------------------------------------------------
  1851.      * For VMS v5.x:
  1852.      *   IO$_SENSEMODE/SETMODE info:  Programming, Vol. 7A, System Programming,
  1853.      *     I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
  1854.      *   sys$assign(), sys$qio() info:  Programming, Vol. 4B, System Services,
  1855.      *     System Services Reference Manual, pp. sys-23, sys-379
  1856.      *   fixed-length descriptor info:  Programming, Vol. 3, System Services,
  1857.      *     Intro to System Routines, sec. 2.9.2
  1858.      * GRR, 15 Aug 91
  1859.   ---------------------------------------------------------------------------*/
  1860.     static struct dsc$descriptor_s DevDesc =
  1861.         {9, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$INPUT"};
  1862.      /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
  1863.     static short           DevChan, iosb[4];
  1864.     static long            i, status;
  1865.     static unsigned long   oldmode[2], newmode[2];   /* each = 8 bytes */
  1866.   
  1867.  
  1868. /*---------------------------------------------------------------------------
  1869.     Assign a channel to standard input.
  1870.   ---------------------------------------------------------------------------*/
  1871.  
  1872.     status = sys$assign(&DevDesc, &DevChan, 0, 0);
  1873.     if (!(status & 1))
  1874.         return status;
  1875.  
  1876. /*---------------------------------------------------------------------------
  1877.     Use sys$qio and the IO$_SENSEMODE function to determine the current tty
  1878.     status (for password reading, could use IO$_READVBLK function instead,
  1879.     but echo on/off will be more general).
  1880.   ---------------------------------------------------------------------------*/
  1881.  
  1882.     status = sys$qio(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0,
  1883.                      oldmode, 8, 0, 0, 0, 0);
  1884.     if (!(status & 1))
  1885.         return status;
  1886.     status = iosb[0];
  1887.     if (!(status & 1))
  1888.         return status;
  1889.  
  1890. /*---------------------------------------------------------------------------
  1891.     Copy old mode into new-mode buffer, then modify to be either NOECHO or
  1892.     ECHO (depending on function argument opt).
  1893.   ---------------------------------------------------------------------------*/
  1894.  
  1895.     newmode[0] = oldmode[0];
  1896.     newmode[1] = oldmode[1];
  1897.     if (opt == 0)
  1898.         newmode[1] |= TT$M_NOECHO;                      /* set NOECHO bit */
  1899.     else
  1900.         newmode[1] &= ~((unsigned long) TT$M_NOECHO);   /* clear NOECHO bit */
  1901.  
  1902. /*---------------------------------------------------------------------------
  1903.     Use the IO$_SETMODE function to change the tty status.
  1904.   ---------------------------------------------------------------------------*/
  1905.  
  1906.     status = sys$qio(0, DevChan, IO$_SETMODE, &iosb, 0, 0,
  1907.                      newmode, 8, 0, 0, 0, 0);
  1908.     if (!(status & 1))
  1909.         return status;
  1910.     status = iosb[0];
  1911.     if (!(status & 1))
  1912.         return status;
  1913.  
  1914. /*---------------------------------------------------------------------------
  1915.     Deassign the sys$input channel by way of clean-up, then exit happily.
  1916.   ---------------------------------------------------------------------------*/
  1917.  
  1918.     status = sys$dassgn(DevChan);
  1919.     if (!(status & 1))
  1920.         return status;
  1921.  
  1922.     return SS$_NORMAL;   /* we be happy */
  1923.  
  1924. } /* end function echo() */
  1925.  
  1926.  
  1927. #else /* !VMS */
  1928.  
  1929. local int echofd = -1;  /* file descriptor whose echo is off */
  1930.  
  1931. void echoff(f)
  1932. int f;                  /* file descriptor to turn echo off on */
  1933. /* Turn echo off for file descriptor f.  Assumes that f is a tty device. */
  1934. {
  1935.   struct sgttyb sg;     /* tty device structure */
  1936.  
  1937.   echofd = f;
  1938.   GTTY(f, &sg);                                 /* get settings */
  1939.   sg.sg_flags &= ~ECHO;                         /* turn echo off */
  1940.   STTY(f, &sg);
  1941. }
  1942.  
  1943. void echon()
  1944. /* Turn echo back on for file descriptor echofd. */
  1945. {
  1946.   struct sgttyb sg;     /* tty device structure */
  1947.  
  1948.   if (echofd != -1)
  1949.   {
  1950.     GTTY(echofd, &sg);                          /* get settings */
  1951.     sg.sg_flags |= ECHO;                        /* turn echo on */
  1952.     STTY(echofd, &sg);
  1953.     echofd = -1;
  1954.   }
  1955. }
  1956.  
  1957. #endif /* ?VMS */
  1958.  
  1959. #endif /* !MSDOS */
  1960.  
  1961.  
  1962. char *getp(m, p, n)
  1963. char *m;                /* prompt for password */
  1964. char *p;                /* return value: line input */
  1965. int n;                  /* bytes available in p[] */
  1966. /* Get a password of length n-1 or less into *p using the prompt *m.
  1967.    The entered password is not echoed.  Return p on success, NULL on
  1968.    failure (can't get controlling tty). */
  1969. {
  1970.   char c;               /* one-byte buffer for read() to use */
  1971.   int i;                /* number of characters input */
  1972.   char *w;              /* warning on retry */
  1973.  
  1974. #ifndef MSDOS
  1975. #ifndef VMS
  1976.   int f;                /* file decsriptor for tty device */
  1977.  
  1978.   /* Turn off echo on tty */
  1979.   if (!isatty(2))
  1980.     return NULL;                                /* error if not tty */
  1981.   if ((f = open(ttyname(2), 0, 0)) == -1)
  1982.     return NULL;
  1983. #endif /* !VMS */
  1984.   echoff(f);                                    /* turn echo off */
  1985. #endif /* !MSDOS */
  1986.  
  1987.   /* Get password */
  1988.   w = "";
  1989.   do {
  1990. #ifdef VMS   /* bug:  VMS adds '\n' to NULL fputs (apparently) */
  1991.     if (*w)
  1992. #endif /* VMS */
  1993.     fputs(w, stderr);                           /* warning if back again */
  1994.     fputs(m, stderr);                           /* prompt */
  1995.     fflush(stderr);
  1996.     i = 0;
  1997.     do {                                        /* read line, keeping n */
  1998. #ifdef MSVMS
  1999.       if ((c = (char)getch()) == '\r')
  2000.         c = '\n';
  2001. #else /* !MSVMS */
  2002.       read(f, &c, 1);
  2003. #endif /* ?MSVMS */
  2004.       if (i < n)
  2005.         p[i++] = c;
  2006.     } while (c != '\n');
  2007.     putc('\n', stderr);  fflush(stderr);
  2008.     w = "(line too long--try again)\n";
  2009.   } while (p[i-1] != '\n');
  2010.   p[i-1] = 0;                                   /* terminate at newline */
  2011.  
  2012. #ifndef MSDOS
  2013.   echon();                                      /* turn echo back on */
  2014. #ifndef VMS
  2015.   close(f);
  2016. #endif /* !VMS */
  2017. #endif /* !MSDOS */
  2018.  
  2019.   /* Return pointer to password */
  2020.   return p;
  2021. }
  2022.  
  2023. #endif /* ?CRYPT */
  2024.  
  2025.  
  2026. #ifdef ZMEM
  2027.  
  2028. /************************/
  2029. /*  Function memset()  */
  2030. /************************/
  2031.  
  2032. /*
  2033.  * memset - for systems without it
  2034.  *  bill davidsen - March 1990
  2035.  */
  2036.  
  2037. char *
  2038. memset(buf, init, len)
  2039. register char *buf;     /* buffer loc */
  2040. register int init;      /* initializer */
  2041. register unsigned int len;   /* length of the buffer */
  2042. {
  2043.     char *start;
  2044.  
  2045.     start = buf;
  2046.     while (len--) *(buf++) = init;
  2047.     return(start);
  2048. }
  2049.  
  2050.  
  2051. /************************/
  2052. /*  Function memcpy()  */
  2053. /************************/
  2054.  
  2055. char *
  2056. memcpy(dst,src,len)           /* v2.0f */
  2057. register char *dst, *src;
  2058. register unsigned int len;
  2059. {
  2060.     char *start;
  2061.  
  2062.     start = dst;
  2063.     while (len--)
  2064.         *dst++ = *src++;
  2065.     return(start);
  2066. }
  2067.  
  2068.  
  2069. /************************/
  2070. /*  Function memcmp()  */
  2071. /************************/
  2072.  
  2073. int
  2074. memcmp(b1,b2,len)                     /* jpd@usl.edu -- 11/16/90 */
  2075. register char *b1, *b2;
  2076. register unsigned int len;
  2077. {
  2078.  
  2079.     if (len) do {             /* examine each byte (if any) */
  2080.       if (*b1++ != *b2++)
  2081.         return (*((uch *)b1-1) - *((uch *)b2-1));  /* exit when miscompare */
  2082.        } while (--len);
  2083.  
  2084.     return(0);        /* no miscompares, yield 0 result */
  2085. }
  2086.  
  2087. #endif  /* ZMEM */
  2088.  
  2089. #ifdef __TURBOC__
  2090.  
  2091. /************************/
  2092. /*  Function fcalloc()  */
  2093. /************************/
  2094.  
  2095. /* Turbo C malloc() does not allow dynamic allocation of 64K bytes
  2096.  * and farmalloc(64K) returns a pointer with an offset of 8, so we
  2097.  * must fix the pointer. Warning: the pointer must be put back to its
  2098.  * original form in order to free it.
  2099.  * For MSC, use halloc instead of this function (see tailor.h).
  2100.  */
  2101. void far * fcalloc(items, size)
  2102.     unsigned items; /* number of items */
  2103.     unsigned size;  /* item size */
  2104. {
  2105.     void far * buf = farmalloc((ulg)items*size + 16L);
  2106.     /* Normalize the pointer to seg:0 */
  2107.     *((int*)&buf+1) += ((unsigned)((uch*)buf-0) + 15) >> 4;
  2108.     *(int*)&buf = 0;
  2109.     return buf; /* buf stays NULL if alloc failed */
  2110. }
  2111.  
  2112. #endif /* __TURBOC__ */
  2113.